package com.why.handler;

import com.why.enums.ErrorEnum;
import com.why.exception.RpcException;
import com.why.message.RpcRequest;
import com.why.message.RpcResponse;
import com.why.pool.ThreadPoolFactroy;
import com.why.provider.ServiceProvider;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;

/**
 * @program: why-rpc-framework
 * @description:通道处理程序，完成对获取到的数据的处理
 * @author: @why
 * @create: 2021-03-16 10:03
 **/
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private ServiceProvider provider;
    private  static ExecutorService poolService;

    public NettyServerHandler(ServiceProvider provider) {
        this.provider = provider;
    }

    static {
        poolService= ThreadPoolFactroy.getExecutorService("netty-server-worker");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("通道被激活。。。");
        super.channelInactive(ctx);
    }

    /**
     *
     * @param ctx：netty的上下文对象，在这里可以完成各种读写的操作。
     * @param msg：保存 Channel 相关的所有上下文信息，同时关联一个 ChannelHandler 对象
     *           ChannelHandlerContext 中包含一个具体的事件处理器 ChannelHandler，
     *           同时 ChannelHandlerContext 中也绑定了对应的 pipeline 和 Channel 的信息，方便对 ChannelHandler 进行调用。
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest msg)  {
         try {
             log.info("通道收到远程发送过来的请求:{}，开始进行请求处理",msg);
             log.info("去服务中心获取服务。。。");
             Object service = provider.getRegisterService(msg.getInterfaceName());
             System.out.println(poolService);
             poolService.execute(()->{
                 log.info("将请求交给线程{}去处理请求。。。",Thread.currentThread().getName());

                 Object result = RequestHandler.handler(service, msg);
                 log.info("处理请求完成，获得的数据为:"+result);
                 log.info("将数据写回开始。。。");
                 ChannelFuture future = ctx.writeAndFlush(RpcResponse.isSuccess(result));
                 future.addListener(ChannelFutureListener.CLOSE);

             });
         }catch (Exception e){
                log.info("nett-server-handler处理程序发生未知异常。。。",e);
                throw new RpcException(ErrorEnum.NOT_FOUND);

         }finally {
             //从InBound里读取的ByteBuf要手动释放，还有自己创建的ByteBuf要自己负责释放。这两处要调用这个release方法。
             //write Bytebuf到OutBound时由netty负责释放，不需要手动调用release
             ReferenceCountUtil.release(msg);
         }



    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("服务端handler发生了异常。。。");
        super.exceptionCaught(ctx, cause);
    }
}
